<?php

/* 20101102 - add add_to_table, delete_from_table 
 * 20101103 - change throw exception
 * 20101113 - added db_selectallrow_hash by Terry
 * 20101115 - modified return value of db_do, delete*_from_table
 *
 */
#
#some example
#db_select_one :
#$count = db_select_one($dbh_r, "select count(*) from $table where id=?", $id);
#$count = db_select_one($dbh_r, "select count(*) from $table where gen=? and mon_status=?", array($gender, $mon_status));
#
#
#db_selectrow_array
#list($mid, $email) = db_selectrow_array($dbh_r, "select mid, email from nmg_login where id=?", $id);
#$a_row = db_selectrow_array($dbh_r, "select mid, email, name, recentlogin from nmg_login where id=?", $id);
#c$mid = $a_row[0];
#
#
#db_selectrow_hash
#$h_row = db_selectrow_hash($dbh_r, "select mid, email, name, recentlogin from nmg_login where id=?", $id);
#$mid = $h_row['mid']
#
#db_selectcol_array
#$a_mid = db_selectcol_array($dbh_r, "select mid from member where gen=1");

#
#db_selectcol_hash
#$h_mid_login = db_selectcol_array($dbh_r, "select mid, recentlogin from member limit 20");
#foreach ( $h_mid_login as $mid =>$recentlogin){
#  echo "$mid =>$recentlogin";
#}
#
#
#db_do
#db_do($dbh_w, "update member set recentlogin=NOW() where mid=?", $mid);
#db_do($dbh_w, "insert into login_history (mid, recentlogin) values (?,?)", array($mid, $recentlogin) );


  function db_select_one($dbh_r, $sqlstr, $a_bind_data=array()){
  	//error_log('db_selectrow_array'.$sqlstr);
    if (!is_array($a_bind_data)) $a_bind_data = array($a_bind_data); # single string, wrap it as to array
  	$sth = $dbh_r->prepare($sqlstr);
	  $sth->execute($a_bind_data);
	  $a_result = array();
	  try{
	    $a_result = $sth->fetch();	
	  } catch (Exception $e){
	  	throw new Exception('db_select_one(): Error in SQL?:'.$e->getMessage(), 310);
	  }  
	  
	  return isset($a_result[0])?$a_result[0]:null;
  }

  function db_selectrow_array($dbh_r, $sqlstr, $a_bind_data=array()){
  	//error_log('db_selectrow_array'.$sqlstr);
    if (!is_array($a_bind_data)) $a_bind_data = array($a_bind_data); # single string, wrap it as to array
  	$sth = $dbh_r->prepare($sqlstr);
	  $sth->execute($a_bind_data);
	  $a_result = array();
	  try{
	    $a_result = $sth->fetch();	
	  } catch (Exception $e){
	  	throw new Exception('db_selectrow_array(): Error in SQL?:'.$e->getMessage(), 311);
	  }  
	  return $a_result;
  }
  
  function db_selectrow_hash($dbh_r, $sqlstr, $a_bind_data=array()){
    if (!is_array($a_bind_data)) $a_bind_data = array($a_bind_data); # single string, wrap it as to array
  	$sth = $dbh_r->prepare($sqlstr);
	  $sth->execute($a_bind_data);
	  $h_result = array();
	  try{
	    $h_result = $sth->fetch(PDO::FETCH_ASSOC);
	  } catch (Exception $e){
	  	throw new Exception('db_selectrow_hash(): Error in SQL?:'.$e->getMessage(), 312);
	  }
	  return $h_result;
  } 

  function db_selectallrow_hash($dbh_r, $sqlstr, $a_bind_data=array()){
    if (!is_array($a_bind_data)) $a_bind_data = array($a_bind_data); # single string, wrap it as to array
  	$sth = $dbh_r->prepare($sqlstr);
	  $sth->execute($a_bind_data);
	  $h_result = array();
	  try{
	    $h_result = $sth->fetchAll(PDO::FETCH_ASSOC);
	  } catch (Exception $e){
	  	throw new Exception('db_selectrow_hash(): Error in SQL?:'.$e->getMessage(), 312);
	  }
	  return $h_result;
  } 
  
  /*
   * only select the first column
   */
  function db_selectcol_array($dbh_r, $sqlstr, $a_bind_data=array()){
    if (!is_array($a_bind_data)) $a_bind_data = array($a_bind_data); # single string, wrap it as to array
  	$sth = $dbh_r->prepare($sqlstr);
    $sth->execute($a_bind_data);
    $a_result = array();
    try{
	    while ($row = $sth->fetch()){
	    	array_push($a_result, $row[0]);
	    }
	  } catch (Exception $e){
	  	throw new Exception('db_selectcol_array(): Error in SQL?:'.$e->getMessage(), 313);
	  }
	 
	  return $a_result;
  }

  /*
   * return a hash with first column as key and 2nd colun as value.
   * Please note it will only select the first 2 columns
   * @return hash 
   */
  function db_selectcol_hash($dbh_r, $sqlstr, $a_bind_data=array()){
    if (!is_array($a_bind_data)) $a_bind_data = array($a_bind_data); # single string, wrap it as to array
  	$sth = $dbh_r->prepare($sqlstr);
    $sth->execute($a_bind_data);
    $h_result;
    try{
	    while ($row = $sth->fetch()){
	    	$h_result[$row[0]] = $row[1];
	    }
	  } catch (Exception $e){
	  	throw new Exception('db_selectcol_hash(): Error in SQL?:'.$e->getMessage(), 314);
	  }
	 
	  return $h_result;
  }
  
  
  
  /*
   * 
   */
  function db_do($dbh_rw, $sqlstr, $a_bind_data=array()){
    if (!is_array($a_bind_data)) $a_bind_data = array($a_bind_data); # single string, wrap it as to array
    try{
	    $sth = $dbh_rw->prepare($sqlstr);
      $sth->execute($a_bind_data);
      return $sth->rowCount();
	  } catch (Exception $e){
	  	throw new Exception('db_do(): Error in SQL?:'.$e->getMessage(), 315);
	  }
	 
	  return 0;
  }  
  
  function db_last_insert_id($dbh_w){
  	return $dbh_w->lastInsertId();
  }
  
  function db_escape($str)
  {
          $search=array("\\","\0","\n","\r","\x1a","'",'"');
          $replace=array("\\\\","\\0","\\n","\\r","\Z","\'",'\"');
          return str_replace($search,$replace,$str);
  }
#############################################################################


  /* Descriptioin
   *   return $a_column : column from $table
   */
  function get_column_name($dbh_r, $table){
  	$i=0;
		$sth = $dbh_r->query("select * from $table where 1=0");
		$a_column_name = array();
		while ($meta = $sth->getColumnMeta($i++)) {
	    array_push($a_column_name, $meta['name']); // get column name , push in an array
	  }
	  return $a_column_name;
  }


  
#############################################################################

	function update_table($dbh_w, $table, $mixed_data=array(), $h_feature=array()){
    $key_name = get_hash_param($h_feature, '#KEY#', 'id'); // name of the pk column
  
    $cgiapp_obj = '';

		$data_from_post = 0;
		if ($mixed_data instanceof CGIApplication) {
			  $data_from_post =1;
			  $cgiapp_obj = $mixed_data;
			  $a_input_field  = array_keys($_POST); // only support post
			  $key_value      = $cgiapp_obj->q_param($key_name);
		  
		} else {
			// to be implemented for non-http update
			$a_input_field = array_keys($mixed_data);
			$key_value     = $mixed_data[$key_name];
		}


    $a_column_name = get_column_name($dbh_w, $table);

	  $a_update_field = array();
	  $a_update_value = array();
	  foreach ( $a_column_name as $colname ){

	    if (strcmp($colname, $key_name) == 0 ){
	    	 continue; //$colname eq $key
	    }

	    if (! array_key_exists($colname, $h_feature) ){ // column has NO feature defined
	    	if (! in_array($colname, $a_input_field) ) continue; // not in update list

        $mixed_type = $data_from_post == 1 ? $cgiapp_obj->q_param($colname) : $mixed_data[$colname];
	    	if (is_array($mixed_type)){
	    		$value = implode(',', $mixed_type);
	    	} else {
	    		$value = $mixed_type;
	    	}

	      array_push($a_update_field, "$colname=?");
	      array_push($a_update_value, $value);
	    } elseif ($h_feature[$colname] == 'skip' ){
	    	continue;
	    } elseif ($h_feature[$colname] == 'h:checkbox'){
        $mixed_type = $data_from_post == 1 ? $cgiapp_obj->q_param($colname) : $mixed_data[$colname];
	    	if (is_array($mixed_type)){
	    		$value = implode(',', $mixed_type);
	    	} else {
	    		$value = $mixed_type;
	    	}

	      array_push($a_update_field, "$colname=?");
	      array_push($a_update_value, $value);	    		
      } elseif ($h_feature[$colname] == 'boolean' ){
      	$value = $data_from_post == 1 ? $cgiapp_obj->q_param($colname) : $mixed_data[$colname];
      	if ($value != 1) $value = 0;
      	array_push($a_update_field, "$colname=?");
	      array_push($a_update_value, $value);
	   	} elseif ($h_feature[$colname] == 'lastmodify'){
	   	    array_push($a_update_field, "$colname=NOW()");	
	    } else {
	    	throw new CgiappErrorException(63, 'Unsupported feature in update_table()');
	    }
	  }


	  $update = implode(',', $a_update_field);
	  array_push($a_update_value, $key_value);
#    if ($this->debug_sql > 0){
#      $this->log_error('sql', "update $table set $update where $key_name =?".implode(", ", $a_update_value));
#    }
	  $sth = $dbh_w->prepare("update $table set $update where $key_name =?");
	  $sth->execute($a_update_value);
	  $rows_affected = $sth->rowCount();
	  return $rows_affected;
	}



	function update_table_multiple_row($dbh_w, $table, $mixed_data='HTTP_POST', $h_feature=array()){  
		$key_name = get_hash_param($h_feature, '#KEY#', 'id'); // name of the pk column
	  $data_from_post = 0;

    $cgiapp_obj = '';

		$data_from_post = 0;
		if ($mixed_data instanceof CGIApplication) {
			  $data_from_post =1;
			  $cgiapp_obj = $mixed_data;
			  	  
			  $a_input_field = array_keys($_POST); // only support post
			  $a_keys        = $cgiapp_obj->q_param($key_name);
		} else {
			$a_input_field = array_keys($mixed_data);
			$a_keys        = $mixed_data[$key_name];
			//throw new CgiappErrorException(64, 'update_table_multiple_row(): invalid parameter ($mixed_data): only HTTP_POST is supported');
			// to be implemented for non-http update
		}

		$a_column_name = get_column_name($dbh_w, $table);
	  $a_change_id = array();

	  foreach ($a_keys as $row_key){
	    $a_update_field = array();
	    $a_update_value = array();

	    foreach ( $a_column_name as $colname ){
	    	if (strcmp($colname, $key_name) == 0 ){  //$colname eq $key
		    	 continue;
		    }
	      $q_param_name = $colname.'_'.$row_key;

	    	if (! array_key_exists($colname, $h_feature) ){ // column has NO feature defined, !defined($feature{$colname}
	        if (! in_array($q_param_name, $a_input_field) )  continue; // not in update list

	      	$mixed_type = $data_from_post == 1 ? $cgiapp_obj->q_param($q_param_name) : $mixed_data[$q_param_name];
		    	if (is_array($mixed_type)){
		    		$value = implode(',', $mixed_type);
		    	} else {
		    		$value = $mixed_type;
		    	}
		    	
		      array_push($a_update_field, "$colname=?");
		      array_push($a_update_value, $value);
		    } elseif ($h_feature[$colname] == 'h:checkbox'){
	        $mixed_type = $data_from_post == 1 ? $cgiapp_obj->q_param($q_param_name) : $mixed_data[$q_param_name];
		    	if (is_array($mixed_type)){
		    		$value = implode(',', $mixed_type);
		    	} else {
		    		$value = $mixed_type;
		    	}
	
		      array_push($a_update_field, "$colname=?");
		      array_push($a_update_value, $value);  
	      } elseif ($h_feature[$colname] == 'boolean'){
   
	      	$value = $data_from_post == 1 ? $cgiapp_obj->q_param($q_param_name) : $mixed_data[$q_param_name];
	      	if ($value != 1) $value = 0;
	      	array_push($a_update_field, "$colname=?");
		      array_push($a_update_value, $value);
	   	  } elseif ($h_feature[$colname] == 'lastmodify'){
	   	    array_push($a_update_field, "$colname=NOW()");	
	      } elseif ($h_feature[$colname] == 'skip' ){
		    	continue;
	      } else {
	    		throw new CgiappErrorException(64, 'Unsupported feature in update_table_multiple_row()');
	      }

	    }

	    $update = implode(',', $a_update_field);
		  if ($update != ''){
			  array_push($a_update_value, $row_key);
#        if ($this->debug_sql > 0){
#		      $this->log_error('sql', "update $table set $update where $key_name =?".implode(',',$a_update_value));
#        }
			  $sth = $dbh_w->prepare("update $table set $update where $key_name =?");
			  $sth->execute($a_update_value);
			  $rows_affected = $sth->rowCount();
			  
		    if ($rows_affected > 0) array_push($a_change_id, $row_key);
	    }
	  }

	  return $a_change_id;
	}

#################


  function delete_from_table($dbh, $table, $mixed_data='HTTP_POST' ,$h_feature=array()){

		$key_name    = get_hash_param($h_feature, '#KEY#', 'id'); // name of the pk column
	  $delete_mode = get_hash_param($h_feature, '#DELETE_MODE#', 'hidden');
	  if ($delete_mode != 'delete') $delete_mode = 'hidden';

	  $key_to_delete = 0;
    $cgiapp_obj = '';

		if ($mixed_data instanceof CGIApplication) {
			  $cgiapp_obj = $mixed_data;
			  $key_to_delete = $cgiapp_obj->get_param('pq',$key_name, 0, 'int');
			  if ($key_to_delete == 0){
			    throw new Exception('delete_from_table(): invalid parameter - Invalid IP to delete', 70);
			  }
			  //$this->errorlog("delete_from_table key - $key_name");
		
		} else {
			$key_to_delete = $mixed_data[$key_name];
		}

    

		$a_column_name = get_column_name($dbh, $table);
		$status_column_name = get_hash_param($h_feature, '#STATUS_FIELD#', 'status');
		if ($delete_mode != 'delete' && ! in_array($status_column_name, $a_column_name) ){
			throw new Exception('delete_from_table(): status field not exists in table', 72);
		}

   	//$this->errorlog("update $table set $status_column_name=0 where $key_name=$row_key");
   	if ($delete_mode == 'hidden'){
  	  $sth = $dbh->prepare("update $table set $status_column_name=0 where $key_name=?");
		  $sth->execute(array($key_to_delete));
		  //$this->errorlog("update $table set $status_column_name=0 where $key_name=?$key_to_delete");
		} elseif($delete_mode == 'delete'){
			//$this->errorlog("delete from $table where $key_name=$key_to_delete");
		  $sth = $dbh->prepare("delete from $table where $key_name=?");
		  $sth->execute(array($key_to_delete));
		}

  }
  
  
  function delete_multiple_from_table($dbh, $table, $mixed_data='HTTP_POST' ,$h_feature=array()){
		$key_name    = get_hash_param($h_feature, '#KEY#', 'id'); // name of the pk column
	  $delete_mode = get_hash_param($h_feature, '#DELETE_MODE#', 'hidden');
	  
	  if ($delete_mode != 'delete') $delete_mode = 'hidden';

    $cgiapp_obj = '';

		if ($mixed_data instanceof CGIApplication) {
			  $cgiapp_obj = $mixed_data;
			  $a_input_field = array_keys($_POST); // only support post
			  $a_keys        = $cgiapp_obj->q_param('mselected_'.$key_name); // we may support this field as configurable so that not only cms can use
		} else {
			$a_keys = $mixed_data[$key_name];
		}

		$a_column_name = get_column_name($dbh, $table);
		$status_column_name = get_hash_param($h_feature, '#STATUS_FIELD#', 'status');
		if ($delete_mode != 'delete' && ! in_array($status_column_name, $a_column_name) ){
			throw new Exception('delete_multiple_from_table(): status field not exists in table', 76);
		}

	  $a_change_id = array();
	  foreach ($a_keys as $row_key){
	   	//$this->errorlog("update $table set $status_column_name=0 where $key_name=$row_key");
	   	if ($delete_mode == 'hidden'){
	   		$sth = $dbh->prepare("update $table set $status_column_name=0 where $key_name=? and status=1");
			  $sth->execute(array($row_key));
			  if( $sth->rowCount() > 0){
			    	array_push($a_change_id, $row_key);
			  } 
			  
			} elseif($delete_mode == 'delete'){
			  $sth = $dbh->prepare("delete from $table where $key_name=?");
			  $sth->execute(array($row_key));
			  if( $sth->rowCount() > 0){
			  	  array_push($a_change_id, $row_key);
			  } 
			}
	  }
    return $a_change_id;
  }
  


############################

	function add_to_table($dbh, $table, $mixed_data='HTTP_POST' ,$h_feature=array()){

		$key_name = get_hash_param($h_feature, '#KEY#', 'id');
    $null_to_string = get_hash_param($h_feature, '#NULL_TO_STRING#', false); # default disable this auto fix/convert
    
		$data_from_post = 0;

    $cgiapp_obj = '';

		$data_from_post = 0;
		if ($mixed_data instanceof CGIApplication) {
			  $data_from_post =1;
			  $cgiapp_obj = $mixed_data;
			  $a_input_field = array_keys($_POST); // only support post
			  $key_value     = $cgiapp_obj->q_param($key_name);
		
		} else {
			$a_input_field = array_keys($mixed_data);
			$key_value     = isset($mixed_data[$key_name])?$mixed_data[$key_name]:'';
		}

    $a_column_name = get_column_name($dbh, $table);
	  $a_add_field = array();
	  $a_add_placeholder = array();
	  $a_add_value = array();
	  foreach ( $a_column_name as $colname ){

	    if (strcmp($colname, $key_name) == 0 ){
	    	 continue; //$colname eq $key
	    }

	    if (! array_key_exists($colname, $h_feature) ){ // column has NO feature defined
	    	if (! in_array($colname, $a_input_field) ) continue; // not in update list

	      $mixed_type = $data_from_post == 1 ? $cgiapp_obj->q_param($colname) : $mixed_data[$colname];
	    	if (is_array($mixed_type)){
	    		$value = implode(',', $mixed_type);
	    	} else {
	    		$value = $mixed_type;
	    	}
	    	
	      array_push($a_add_field, "$colname");
	      array_push($a_add_placeholder, '?');
	      array_push($a_add_value, $null_to_string? null_to_string($value): $value);
	    } elseif ($h_feature[$colname] == 'skip' ){
	    	continue;
	   	} elseif ($h_feature[$colname] == 'addtime' || $h_feature[$colname] == 'lastmodify'){
	   	  array_push($a_add_field, "$colname");
	      array_push($a_add_placeholder, 'NOW()');

	    } elseif ( function_exists($h_feature[$colname]) ){
	    	$function_name = $h_feature[$colname];
	    	$value = $data_from_post == 1 ? $cgiapp_obj->q_param($colname) : $mixed_data[$colname];
	    	$value = $function_name($value);

	      array_push($a_add_field, "$colname");
	      array_push($a_add_placeholder, '?');
	      array_push($a_add_value, $null_to_string? null_to_string($value): $value);
	    } else { 	    	
	    	// column in table has no data in form
	    }
	  }

	  if (!empty_string($key_value)){ // $key_value eq '', add with specified ID
	    array_push($a_add_field, "$key_name");
	    array_push($a_add_placeholder, '?');
	    array_push($a_add_value, $key_value);
	  }

	  $add_part         = implode(',', $a_add_field);
	  $placeholder_part = implode(',', $a_add_placeholder);
	 
	  $sth = $dbh->prepare("insert into $table ($add_part) values ($placeholder_part)");
	  $sth->execute($a_add_value);
#	  if ($this->debug_sql > 0){
#      $this->log_error('sql', "insert into $table ($add_part) values ($placeholder_part); ".implode(", ", $a_add_value));
#    }
	  return $dbh->lastInsertId();
	  //$rows_affected = $sth->rowCount();
	  //return $rows_affected;
	}

 
	/* convert null to ''
	 * avoid error when table do not accept null
	 */
  function null_to_string($string){
	  return isset($string) ? $string:''; 
  }
  

	function add_to_table_multiple_row($dbh, $table, $mixed_data='HTTP_POST', $h_feature=array()){
	
		$key_name = get_hash_param($h_feature, '#KEY#', 'id'); // name of the pk column
 
    $add_with_specified_id = 0;
    $data_from_post = 0;

    $cgiapp_obj = '';

		$data_from_post = 0;
		if ($mixed_data instanceof CGIApplication) {
			  $data_from_post =1;
			  $cgiapp_obj = $mixed_data;
			  $a_input_field = array_keys($_POST); // only support post
			  $a_keys        = $cgiapp_obj->q_param($key_name); // assume add with specified ID
			  if (! is_array($a_keys)){
			    $a_keys = empty($a_keys) ? array() : explode(',', $a_keys); 
			  }
			  $add_with_specified_id = 1;
		  
		} else {
			$a_input_field = array_keys($mixed_data);
			$a_keys = $mixed_data[$key_name]; // assume add with specified ID
			if (! is_array($a_keys)){
			  $a_keys = empty($a_keys) ? array() : explode(',', $a_keys); 
		  }
			$add_with_specified_id = 1;
		}
		
		// check if it is add with specified ID
		if (count($a_keys) == 0){
			$add_with_specified_id = 0;
			$a_keys = range(1,10); 
		}
    $a_fixed_field = get_hash_param($h_feature, '#FIXED_FIELD#', array()); 
		$a_column_name = get_column_name($dbh, $table);
	  $a_change_id   = array(); // hold the id just created.
	  
	  foreach ($a_keys as $row_key){
	  	$a_add_field       = array();
	    $a_add_placeholder = array();
      $a_add_value       = array();
      $is_emtpy_row      = 1; // assume we have data to add

	    foreach ( $a_column_name as $colname ){
	    	if (strcmp($colname, $key_name) == 0 ){  //$colname eq $key
		    	 continue;
		    }
		    
		    $is_fixed_field   = 0; // fixed field will not be count in empty row
	      $q_param_name = $colname.'_'.$row_key;
	      if (in_array($colname, $a_fixed_field)){
	      	$is_fixed_field=1;
	      	$q_param_name = $colname;
	      }

	    	if (! array_key_exists($colname, $h_feature) ){ // column has NO feature defined, !defined($feature{$colname}
	        if (! in_array($q_param_name, $a_input_field) )  continue; // not in update list
          $mixed_type = $data_from_post == 1 ? $cgiapp_obj->q_param($q_param_name) : $mixed_data[$q_param_name];	      	
		    	if (is_array($mixed_type)){
		    		$value = implode(',', $mixed_type);
		    	} else {
		    		$value = $mixed_type;
		    	}

		      array_push($a_add_field, "$colname");
	        array_push($a_add_placeholder, '?');
  	      array_push($a_add_value, $value);
          if ($is_fixed_field==0 && !empty_string($value)) $is_emtpy_row = 0; // not empty
          
	      } elseif ($h_feature[$colname] == 'boolean'){
	      	$value = $data_from_post == 1 ? $cgiapp_obj->q_param($q_param_name) : $mixed_data[$q_param_name];	      	
	      	if ($value != 1) $value = 0;
	      	array_push($a_add_field, "$colname");
	        array_push($a_add_placeholder, '?');
  	      array_push($a_add_value, $value);
  	      if ($is_fixed_field==0 && !empty_string($value)) $is_emtpy_row = 0; // not empty

	      } elseif ($h_feature[$colname] == 'skip' ){
		    	continue;
	      } 
	       

	    } //end foreach $colname

      
      //
      if( $is_emtpy_row==1 && $add_with_specified_id==0){
      	break; # exit. it do not specify id for add, stop adding data as soon as we find an empty row
      }

      // need to support 2 case: add with id, add using auto_increment id
		  if ($add_with_specified_id==1){ // $key_value eq ''
			  array_push($a_add_field, "$key_name");
		    array_push($a_add_placeholder, '?');
		    array_push($a_add_value, $row_key);
		  }

	    $add_part         = implode(',', $a_add_field);
	    $placeholder_part = implode(',', $a_add_placeholder);
	    //$this->errorlog("insert into $table ($add_part) values ($placeholder_part)".implode(',',$a_add_value));
	    $sth = $dbh->prepare("insert into $table ($add_part) values ($placeholder_part)");
	    $sth->execute($a_add_value);

	    array_push($a_change_id, $dbh->lastInsertId());
	  } // foreach $a_keys

	  return $a_change_id;
	}
  
  
  
  

function copy_row_by_parent_key($dbh_w, $table, $parent_key_name, $copy_key, $new_key, $h_feature){    
  $count = 0;    # count the number of affected row
  
  $a_new_ids = array(); 
  $a_copied_ids = array();
  $condition = isset($h_param['condition'])? $h_param['condition'] : '';
    
  $sth = $dbh->prepare("select * from $table where $foreign_key_name=? $condition");   # for getting col name
  $sth->execute($copy_key);
  $a_column_name = get_column_name($dbh_w, $table);  
  
  while ($h_row = $sth->fetch(PDO::FETCH_ASSOC)){
  	$a_field        = array();
	  $a_value        = array();
	  $a_placeholder  = array();
    $count++;
    foreach ( $a_column_name as $colname ){    
      if (strcmp($colname, $foreign_key_name) == 0){
	      array_push($a_field, $colname);
        array_push($a_value, $new_key);
        array_push($a_placeholder, '?');
        
      } elseif (! array_key_exists($colname, $h_feature) ){ // column has NO feature defined
        array_push($a_field, $colname);
        array_push($a_value, $h_row[$colnamme]);
        
      } elseif ($h_feature[$colname] == 'now') {      	
	      array_push($a_field, $colname);
	      array_push($a_value, 'NOW()');
	      
      } elseif ($h_feature[$colname] == 'auto_increment') {
	      array_push($a_copied_ids, $row[$colname]);
	      
      }
    }

    $field = implode(',', $a_field);
    $value = implode(',', $a_placeholder);
	  $sth = $dbh_w->prepare("insert into $table ($field) values ($placeholder)");
    $sth->execute($a_value);

    $new_key = $dbh_w->lastInsertId();
    array_push($a_new_ids, $new_key);
  }

  return array($count, $a_new_ids, $a_copied_ids);
}
  

function copy_row_by_key($dbh_w, $table, $key_name, $copy_key, $h_feature){
  $count = 0;    # count the number of affected row
  #$a_new_ids = array();   
  $new_key = 0;
  $condition = isset($h_param['condition'])? $h_param['condition'] : '';
  
  try{
    ///while ($h_row = $sth->fetch(PDO::FETCH_ASSOC)){
    if (1){ # temp replace the while...
      $h_row = db_selectrow_hash($dbh_w, "select * from $table where $key_name=? $condition", $copy_key);
      $a_column_name = get_column_name($dbh_w, $table);
      $a_field       = array();
      $a_value       = array();
      $a_placeholder = array();
      $count++;
      
      foreach ( $a_column_name as $colname ){    
        if (strcmp($colname, $key_name) == 0){
           # skip
        } elseif (! array_key_exists($colname, $h_feature) ){ // column has NO feature defined
           array_push($a_field, $colname);
           array_push($a_value, $h_row[$colname]); 
           array_push($a_placeholder,  '?');
        } elseif ($h_feature[$colname] == 'now') {
           array_push($a_field, $colname);
           array_push($a_value, 'NOW()');
        } elseif ($h_feature[$colname] == 'auto_increment') {
          # skip this field
        }
      }
      
      $field       = implode(',', $a_field);
      $placeholder = implode(',', $a_placeholder);
      
      $sth = $dbh_w->prepare("insert into $table ($field) values ($placeholder)");
      $sth->execute($a_value);

      $new_key = $dbh_w->lastInsertId();
      
    }
   } catch (Exception $e){
	  	throw new CgiappErrorException(85, 'copy_row_by_key(): Error in SQL?:'.$e->getMessage());
	 }
  
  return array($count, $new_key);
}

  
   
  
  
  
?>